#pragma once

#include <string>
#include <vector>
#include <fstream>
#include <unordered_map>
#include <unordered_set>
#include <sstream>
#include <unordered_set>

#include "../../Utility/Log/Log.hpp"
#include "../../Utility/Static/Algorithmf.hpp"
#include "../../Utility/Data/NavMessageData/GNSSMesData.hpp"

namespace ns_GNSSMesInput
{
    using namespace ns_Util;
    using namespace ns_Log;

    enum EndLineMarkType
    {
        HeaderPre,
        Comment,
        IonoCorr,
        TimeCorr,
        LeapSecond,
        EndOfHeader,
        DefaultStopMarkType
    };

    std::unordered_map<std::string, EndLineMarkType> EndMark =
        std::unordered_map<std::string, EndLineMarkType>({{"COMMENT", EndLineMarkType::Comment},
                                                          {"IONOSPHERIC CORR", EndLineMarkType::IonoCorr},
                                                          {"TIME SYSTEM CORR", EndLineMarkType::TimeCorr},
                                                          {"LEAP SECONDS", EndLineMarkType::LeapSecond},
                                                          {"END OF HEADER", EndLineMarkType::EndOfHeader}});

    // 负数表示ignore
    const std::vector<std::vector<int>> HeaderPreReadFormat =
        std::vector<std::vector<int>>({
            {9, -11, 1, -19, 1, -19},
            {20, 20, 20},
        });

    const std::vector<int> CommentReadFormat =
        std::vector<int>(
            {60});

    const std::vector<int> IonoCorrReadFormat =
        std::vector<int>(
            {4, -1, 12, 12, 12, 12, -1, 1, -1, 2});

    const std::vector<int> TimeCorrReadFormat =
        std::vector<int>(
            {4, -1, 17, 16, -1, 6, -1, 4, -1, 5, -1, 2, -1});

    const std::vector<int> LeapSecondReadFormat =
        std::vector<int>(
            {6, 6, 6, 6});

    class GNSSMesHeaderReader
    {
    public:
        GNSSMesHeaderReader()
        {
        }

        static int Read(const std::string &fileName, const std::initializer_list<GNSSType> &catchList,
                        std::unordered_map<EndLineMarkType, std::vector<std::vector<std::string>>> *readResult)
        {
            std::unordered_set<GNSSType> catchs(catchList);
            std::string source = PathUtil::Src(fileName);

            std::ifstream inStream(source);
            if (!inStream.is_open())
            {
                Log(Warnning) << "Open File Failed" << '\n';
                return -1;
            }

            int readState = ReadHeader(inStream, catchs, *readResult);

            return readState;
        }

    private:
        static FileReadStateType ReadHeader(std::ifstream &file, const std::unordered_set<GNSSType> &catchs,
                                            std::unordered_map<EndLineMarkType, std::vector<std::vector<std::string>>> &readResult)
        {
            std::string lineReadBuffer;

            // 读取第一行
            {
                std::getline(file, lineReadBuffer);
                int pos = 0;
                readResult[HeaderPre].resize(1);
                for (auto e : HeaderPreReadFormat[0])
                {
                    if (e < 0)
                        pos += -e;
                    else
                    {
                        readResult[EndLineMarkType::HeaderPre][0].push_back(std::string(lineReadBuffer.begin() + pos, lineReadBuffer.begin() + pos + e));
                        pos += e;
                    }
                }

                lineReadBuffer.clear();
            }

            // 读取第二行
            {
                std::getline(file, lineReadBuffer);
                int pos = 0;
                for (auto e : HeaderPreReadFormat[1])
                {
                    if (e < 0)
                        pos += -e;
                    else
                    {
                        readResult[HeaderPre][0].push_back(std::string(lineReadBuffer.begin() + pos, lineReadBuffer.begin() + pos + e));
                        pos += e;
                    }
                }

                lineReadBuffer.clear();
            }

            // 读取comment,IonoCorr,TimeCorr和LeapSecond
            {
                int tryCount = 100;

                while (true)
                {
                    std::getline(file, lineReadBuffer);
                    std::string tmp(lineReadBuffer.begin() + 60, lineReadBuffer.end());

                    EndLineMarkType lineMark = EndMark[tmp];

                    switch (lineMark)
                    {
                    case EndLineMarkType::Comment:
                        break;
                    case EndLineMarkType::IonoCorr:
                        ReadIonoCorr(lineReadBuffer,catchs,readResult);
                        break;
                    case EndLineMarkType::TimeCorr:
                        ReadTimeCorr(lineReadBuffer,catchs,readResult);
                        break;
                    case EndLineMarkType::LeapSecond:
                        ReadLeapSecond(lineReadBuffer,catchs,readResult);
                        break;
                    case EndLineMarkType::EndOfHeader:
                        return FileReadStateType::FileReadSuccess;
                        break;
                    default:
                        break;
                    }

                    lineReadBuffer.clear();

                    tryCount--;

                    if (tryCount < 0)
                    {
                        return FileReadStateType::FileReadDefault;
                    }
                }
            }

            return FileReadStateType::FileReadDefault;
        }

        static FileReadStateType ReadIonoCorr(const std::string &lineReadBuffer, const std::unordered_set<GNSSType> &catchs,
                                            std::unordered_map<EndLineMarkType, std::vector<std::vector<std::string>>> &readResult)
        {
            // 检测是否过滤
            {
                const std::string gnssName(lineReadBuffer.c_str(), 4);
                GNSSType gnssType = GNSSTypeUtil::GetGNSSTypeByName(gnssName);

                if (catchs.find(gnssType) == catchs.end())
                    return FileReadStateType::FileReadIgnore;
            }

            std::vector<std::string> ins;
            int pos = 0;
            for (auto e : IonoCorrReadFormat)
            {
                if (e < 0)
                    pos += -e;
                else
                {
                    ins.push_back(std::string(lineReadBuffer.begin() + pos, lineReadBuffer.begin() + pos + e));
                    pos += e;
                }
            }

            readResult[IonoCorr].push_back(ins);
            return FileReadStateType::FileReadSuccess;
        }

        static FileReadStateType ReadTimeCorr(const std::string &lineReadBuffer, const std::unordered_set<GNSSType> &catchs,
                                            std::unordered_map<EndLineMarkType, std::vector<std::vector<std::string>>> &readResult)
        {
            // 检测是否过滤
            {
                const std::string gnssName(lineReadBuffer.c_str(), 4);
                GNSSType gnssType = GNSSTypeUtil::GetGNSSTypeByName(gnssName);

                //读的时候，只取UT
                if (catchs.find(gnssType) == catchs.end() || (gnssName[2] != 'U' || gnssName[3] != 'T'))
                    return FileReadStateType::FileReadIgnore;
            }

            std::vector<std::string> ins;
            int pos = 0;
            for (auto e : TimeCorrReadFormat)
            {
                if (e < 0)
                    pos += -e;
                else
                {
                    ins.push_back(std::string(lineReadBuffer.begin() + pos, lineReadBuffer.begin() + pos + e));
                    pos += e;
                }
            }

            readResult[TimeCorr].push_back(ins);
            return FileReadStateType::FileReadSuccess;
        }

        static FileReadStateType ReadLeapSecond(const std::string &lineReadBuffer, const std::unordered_set<GNSSType> &catchs,
                                            std::unordered_map<EndLineMarkType, std::vector<std::vector<std::string>>> &readResult)
        {
            std::vector<std::string> ins;
            int pos = 0;
            for (auto e : LeapSecondReadFormat)
            {
                if (e < 0)
                    pos += -e;
                else
                {
                    ins.push_back(std::string(lineReadBuffer.begin() + pos, lineReadBuffer.begin() + pos + e));
                    pos += e;
                }
            }

            readResult[LeapSecond].push_back(ins);
            return FileReadStateType::FileReadSuccess;
        }
    };

    
}